//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;

namespace Eas.WebCrawler.PlugIns.Selectors {
    /// <summary>Selects whether or not to follow links based on the extension of the link uri.</summary>
    public class ExtensionSelector : Eas.WebCrawler.PlugIns.Selectors.ConditionalSelector{
        /// <summary>Common extensions for movies.</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
        public static string[] MovieExtensions = new string[]{
            ".avi",
            ".ram",
            ".mpg",
            ".mpeg",
            ".wmv",
            ".mov",
            ".mp2",
            ".mpe",
            ".mpa",
            ".m1v",
            ".m2v",
            ".ifo",
            ".vob"
        };

        /// <summary>Common extensions for images.</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
        public static string[] ImageExtensions = new string[]{
            ".bmp",
            ".jpg",
            ".jpeg",
            ".png",
            ".tiff",
            ".gif",
            ".wmf",
            ".emf"
        };

        /// <summary>Common extensions for flash objects.</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
        public static string[] FlashExtensions = new string[]{
            ".swf",
            ".xaml"
        };

        /// <summary>Common extensions for files that are not text (not html).</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
        public static string[] BinaryExtensions = new string[]{
            ".swf",
            ".xaml",
            ".bmp",
            ".jpg",
            ".jpeg",
            ".png",
            ".tiff",
            ".gif",
            ".wmf",
            ".emf",
            ".avi",
            ".ram",
            ".mpg",
            ".mpeg",
            ".wmv",
            ".mov",
            ".mp2",
            ".mpe",
            ".mpa",
            ".m1v",
            ".m2v",
            ".ifo",
            ".vob"
        };

        /// <summary>Common extensions that are text (html).</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
        public static string[] HtmlExtensions = new string[]{
            ".htm",
            ".html",
            ".php",
            ".asp",
            ".aspx",
            ".jsp"
        };

        /// <summary>Common extensions for text files that are not html.</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
        public static string[] HtmlSupportFiles = new string[]{
            ".js",
            ".css"
        };

        /// <summary>The extensions that should be followed.</summary>
        /// <remarks>Backing field for the FollowedExtensions property.</remarks>
        /// <seealso cref="FollowedExtensions"/>
        private string[] _FollowedExtensions;

        /// <summary>Whether or not to use the trueSelector for default pages (those that are liked to using only the directory).</summary>
        /// <remarks>Backing field for the UseTrueSelectorForDirectoryUris property.</remarks>
        /// <seealso cref="UseTrueSelectorForDirectoryUris"/>
        private bool _UseTrueSelectorForDirectoryUris;

        /// <summary>Constructs a selector based on two selectors which are chosen based on whether or not the request has an extension in any of the arrays in <paramref name="extensions"/>.</summary>
        /// <param name="trueSelector">The selector to call if the the request has an extension in <paramref name="extensions"/>.</param>
        /// <param name="falseSelector">The selector to call if the the request does not have an extension in <paramref name="extensions"/>.</param>
        /// <param name="useTrueSelectorForDirectoryUris">Whether or not to use the true selector if the request points to the default page of a directory (for example http://www.google.com/ which has no extension).</param>
        /// <param name="extensions">A collection of arrays of extensions to look for.</param>
        public ExtensionSelector(Eas.WebCrawler.Interfaces.LinkSelector trueSelector, Eas.WebCrawler.Interfaces.LinkSelector falseSelector, bool useTrueSelectorForDirectoryUris, params string[][] extensions) : this (trueSelector, falseSelector, useTrueSelectorForDirectoryUris, Eas.WebCrawler.Common.Collections.ArrayHelper.Combine(extensions)) {}

        /// <summary>Constructs a selector based on two selectors which are chosen based on whether or not the request has an extension in <paramref name="extensions"/>.</summary>
        /// <param name="trueSelector">The selector to call if the the request has an extension in <paramref name="extensions"/>.</param>
        /// <param name="falseSelector">The selector to call if the the request does not have an extension in <paramref name="extensions"/>.</param>
        /// <param name="useTrueSelectorForDirectoryUris">Whether or not to use the true selector if the request points to the default page of a directory (for example http://www.google.com/ which has no extension).</param>
        /// <param name="extensions">An array of extensions to look for.</param>
        private ExtensionSelector(Eas.WebCrawler.Interfaces.LinkSelector trueSelector, Eas.WebCrawler.Interfaces.LinkSelector falseSelector, bool useTrueSelectorForDirectoryUris, params string[] extensions)
            : base(trueSelector, falseSelector, null) {
            _FollowedExtensions = new string[extensions.Length];
            for (int i = 0; i < extensions.Length; i++) {
                _FollowedExtensions[i] = extensions[i].ToLowerInvariant();
            }
            Array.Sort<string>(_FollowedExtensions);
            this.ConditionalDelegate = new RequestFilterDelegate(ExtensionFound);
            this._UseTrueSelectorForDirectoryUris= useTrueSelectorForDirectoryUris;
        }

        /// <summary>Whether or not to use the trueSelector for default pages (those that are liked to using only the directory).</summary>
        public bool UseTrueSelectorForDirectoryUris {
            get { return _UseTrueSelectorForDirectoryUris; }
        }

        /// <summary>The extensions that should be followed.</summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
        public string[] FollowedExtensions {
            get { return _FollowedExtensions; }
        }

        private bool ExtensionFound(Eas.WebCrawler.Interfaces.Request request) {
            string document = GetDocument(request.Uri).ToLowerInvariant();
            if (document.Length==0)
                return _UseTrueSelectorForDirectoryUris;

            for (int i = 0; i < _FollowedExtensions.Length; ++i) {
                if (document.EndsWith(_FollowedExtensions[i], StringComparison.Ordinal))
                    return true;
            }
            return false;
        }

        internal static string GetDocument(Uri uri) {
            string[] segments = uri.AbsolutePath.Split('/');
            string last = segments[segments.Length - 1];
            if (last.IndexOf('.' ) != -1)
                return last;
            else
                return string.Empty;
        }
    }
}
